package com.ly.hotel.cloud;

import android.content.Context;
import android.os.Build;
import android.util.Log;
import android.view.KeyEvent;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.ly.hotel.MyBaseActivity;
import com.ly.hotel.common.Constants;
import com.ly.hotel.common.MyApplication;
import com.ly.hotel.common.MyKeyEventCode;
import com.ly.hotel.model.ClouldPushBean;
import com.ly.hotel.msgevent.CloudPlayVideoEvent;
import com.ly.hotel.msgevent.CloudSocketIdReportEvent;
import com.ly.hotel.msgevent.ControlVodEvent;
import com.ly.hotel.service.MyCloudBackService;
import com.ly.hotel.service.SPABackService;
import com.ly.hotel.util.TouchUtil;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;

import de.greenrobot.event.EventBus;

/*
 * 
 * 这不是一个通用的socketClient
 * 
 * 
 * 
 * */
public class SocketClient extends Thread {
	private static final Gson gson = new GsonBuilder().create();
	public String ip = null;// 连接服务器的IP
	public Integer port = null;// 连接服务器的端口
	private Socket socket = null;// 套节字对象
	private boolean close = false; // 关闭连接标志位，true表示关闭，false表示连接
	private Integer sotimeout = 1 * 1 * 50;// 超时时间，以毫秒为单位,read方法的超时时间，这个方法是堵塞的
	private Proxy proxy = null;
	
	private char[] readBuf = new char[1000];
	public Context context = null;
	private Timer alive_timer = null;
	private Integer tryTimes = 240;//只尝试20分钟，如果超过20分钟没有连接上，就需要重启电视才能用了
	private boolean socketReadThreadRun = true;
	// ------------------------------------------------------------------------------

	public SocketClient(final Proxy proxy, Context context) {
		setIp();
		setPort();
		this.proxy = proxy;
		this.context = context;
		init();
		
		long interval_time = 10000;
		TimerTask task = new TimerTask() {
			@Override
			public void run() {
					//socket.sendUrgentData(0);//发送1个字节的紧急数据，默认情况下，服务器端没有开启紧急数据处理，不影响正常通信
					//Log.i("socket", "发送心跳判断socket是否断开.");
					close = isServerClose(socket);
					
					if(close){
						try { 
							Log.i("socketClient", "重新建立连接：" + getIp() + ":" + getPort());
							//重新连接前清空之前的id号
							MyApplication.clouldCtlUrl = "";
							InetAddress address = InetAddress.getByName(getIp());
							if(proxy != null){
								Log.i("socket", "使用代理服务器联网>>" + proxy.address().toString());
								socket = new Socket(proxy);
								socket.connect(new InetSocketAddress(getIp(), getPort()));
							} else {
								socket = new Socket(address, getPort());
							}
							socket.setKeepAlive(true);
							socket.setSoTimeout(sotimeout);
							close = !Send(socket, "CONN:" + MyCloudBackService.cloudLogsServerIp + ":" +
									(MyCloudBackService.cloudLogsServerPort+1));
							Log.i("socketClient", "建立连接成功：" + getIp() + ":" + getPort());
						} catch (Exception se) {
							Log.i("socketClient", "创建连接失败:" + getIp() + ":" + getPort());
							tryTimes--;
							if(tryTimes<=0){
								alive_timer.cancel();
								alive_timer = null;
								socketReadThreadRun = false;
							}
							close = true;
						}
					}
				}
		};
		
		if(alive_timer == null){
			alive_timer = new Timer(true);
			alive_timer.schedule(task, 100, interval_time);	
		}
	}

	/**
	 * 初始化socket对象
	 */
	public void init() {
		try {
			InetAddress address = InetAddress.getByName(getIp());
			if(proxy != null){
				Log.i("socket", "使用代理服务器联网>>" + proxy.address().toString());
				socket = new Socket(proxy);
				socket.connect(new InetSocketAddress(getIp(), getPort()));
			} else {
				socket = new Socket(address, getPort());
			}
			socket.setKeepAlive(true);// 开启保持活动状态的套接字
			socket.setSoTimeout(sotimeout);// 设置超时时间
			close = !Send(socket,"CONN:" + MyCloudBackService.cloudLogsServerIp + ":" +
					(MyCloudBackService.cloudLogsServerPort+1));// 发送初始数据，发送成功则表示已经连接上，发送失败表示已经断开
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 读数据线程
	 */
	public void run() {
		while (socketReadThreadRun) {
			// ---------读数据---------------------------
			//close = isServerClose(socket);// 判断是否断开
			//断开的判断，改到alive_timer中定时处理
			if (!close && socket != null) {// 没有断开，开始读数据
				
				String readtext = ReadText(socket);
				if (readtext != null && readtext.trim().length() > 0) {
					Log.i("socketClient", "读取数据：" + readtext);
					
					//clouldCtlUrl初始就是空的，第一次收到的数据就是sock的id号
					if(MyApplication.clouldCtlUrl.equals("")){
						Log.i("socketClient", "更新MyApplication.clouldCtlUrl的值");
						JSONObject jsonObject = new JSONObject();   
						try {
							jsonObject.put("crop", MyApplication.authToCompany);
							jsonObject.put("sockid", readtext);
							jsonObject.put("mac", MyApplication.getMAC());
						} catch (JSONException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
				        
						MyApplication.clouldCtlUrl = Constants.DEFAULT_CLOUD_CTRL + "/webapp?app=RemoteCtrl&argv=" + jsonObject.toString();
						
						Log.i("socketClient", "授权地址：" + MyApplication.clouldCtlUrl);
						
						EventBus.getDefault().post(new CloudSocketIdReportEvent(readtext));
//						MyCloudBackService.replyRpc(MyCloudBackService.rpcSockid, "setSockid,"+ readtext);
					} else {
						try{
							ClouldPushBean d = gson.fromJson(readtext, ClouldPushBean.class);
							
							//if(readtext.equals(ClouldPushBean.CMD_PLAY_MOVIE)){
								//播放电影需要传递的参数
								String id = "0";
								
								if(d.getMsg().startsWith("cmd:movie#id=")){
									id = d.getMsg().replace("cmd:movie#id=", "");
									
									try {
										EventBus.getDefault().post(new CloudPlayVideoEvent(Integer.parseInt(id)));
									}catch (Exception se) {
										Log.e("cloudcmd", "云端推送命令出错:" + readtext);
									}
								}else if(d.getMsg().startsWith("cmd:movie#position=")){
									id = d.getMsg().replace("cmd:movie#position=", "");
									Log.i("cloudcmd", "电影快进:" + id);
									try {
										ControlVodEvent event = new ControlVodEvent(ControlVodEvent.VOD_SEEK);
										event.setSeektoPosition(Integer.parseInt(id));
										EventBus.getDefault().post(event);
									}catch (Exception se) {
										Log.e("cloudcmd", "云端推送命令出错:" + readtext);
									}
								}else if(d.getMsg().startsWith("cmd:ctrl#keycode=")){
									id = d.getMsg().replace("cmd:ctrl#keycode=", "");
									Log.i("cloudcmd", id);
									try {
										Integer code = Integer.parseInt(id);
										int keyCode = 0;
										if (code == 19){
											keyCode = KeyEvent.KEYCODE_DPAD_UP;
										} else if(code == 21){
											keyCode = KeyEvent.KEYCODE_DPAD_LEFT;
										} else if(code == 66){
											keyCode = KeyEvent.KEYCODE_ENTER;
										} else if(code == 22){
											keyCode = KeyEvent.KEYCODE_DPAD_RIGHT;
										} else if(code == 20){
											keyCode = KeyEvent.KEYCODE_DPAD_DOWN;
										} else if(code == 184){
											keyCode = KeyEvent.KEYCODE_VOLUME_UP;
										} else if(code == 185){
											keyCode = KeyEvent.KEYCODE_VOLUME_DOWN;
										} else if(code == 4){
											keyCode = KeyEvent.KEYCODE_BACK;
										}else if (code == 502){
											keyCode = MyKeyEventCode.KEYCODE_TV;		//电视
										} else if(code == 223){
											keyCode = MyKeyEventCode.KEYCODE_MOVICE;		//电影
										} else if (code == 206){
											keyCode = MyKeyEventCode.KEYCODE_CALL;		//呼叫
										} else if (code == 89){
											keyCode = MyKeyEventCode.KEYCODE_LIUWEI;			//留位
										}
										if (keyCode != 0 && (MyBaseActivity.getMyBoard())){
											SPABackService.setRemoteCode(keyCode);
										}else {
											if (code == KeyEvent.KEYCODE_ENTER) {
												Log.i("cloudcmd", "手机遥控确认，发送不带锁按键事件.");
												TouchUtil.sendKeyCode(code, 0, false);
											} else {
												TouchUtil.sendKeyCode(code, 0, true);
											}
										}
									}catch (Exception se) {
										se.printStackTrace();
										Log.e("cloudcmd", "云端推送命令出错:" + readtext);
									}
								}else if(d.getMsg().startsWith("cmd:rpc#")){
									id = d.getMsg().replace("cmd:rpc#", "");
									Log.i("cloudcmd", "RPC:" + id);
									
									String buf[] = id.split("\\|");
									if(buf[0].equals("httpJsonGet")){
										String socketid = buf[1];
										//cmd:rpc#httpJsonGet,locale[interface],request
										if(socketid != null && buf[2] != null && buf[3] != null){
											MyCloudBackService.requestRpcHttp(socketid, buf[3], buf[2]);
										}
									} else if(buf[0].equals("udp")){
										String socketid = buf[1];
										//cmd:rpc#udp,locale[interface],request,startTag,endTag,errorStartTag)
										if(socketid != null && buf[2] != null && buf[3] != null){
											MyCloudBackService.requestRpcUdp(socketid, buf[3], buf[4], buf[5], buf[6], buf[2]);
										}
									} else{
										String methodName = buf[0];//第一个是函数名
										String socketid = buf[1];//第二个是sockid
										Object objs = Array.newInstance(Object.class, buf.length-2);//接下来的是参数
										for(int i = 0;i<buf.length-2;i++){
											Array.set(objs, i, buf[i+2]);//buf从2开始，0是函数名,1是sockid
										}
										
										Log.i("cloudcmd", "调用方法:" + methodName + ",参数个数:" + (buf.length-2));
										
										//通过放射机制调用方法名，参数是一个Array，FunctionRpc类里面的方法，
										//全部要使用Object... objs作为参数，然后在方法里面再分解成String方式
										FunctionRpc frpc = new FunctionRpc();
										Method m = frpc.getClass().getDeclaredMethod(methodName,Array.newInstance(Object.class, buf.length-2).getClass());
										String msg = (String) m.invoke(frpc, objs);

										if(msg != null){
											Log.i("cloudcmd", "调用方法返回:" + msg);
											MyCloudBackService.replyRpc(socketid, msg);
										}
										
									}
								}
	
						//	}
						} catch(Exception e){
							Log.e("cloudcmd", "指令解析错误:" + e.getMessage());
						}
					}
				}
			}
			// ---------创建连接-------------------------
			/*while (close) {// 已经断开，重新建立连接
				try {
					Log.i("socketClient", "重新建立连接：" + getIp() + ":" + getPort());
					//重新连接前清空之前的id号
					MyApplication.clouldCtlUrl = "";
					InetAddress address = InetAddress.getByName(getIp());
					if(proxy != null){
						Log.i("socket", "使用代理服务器联网>>" + proxy.address().toString());
						socket = new Socket(proxy);
						socket.connect(new InetSocketAddress(getIp(), getPort()));
					} else {
						socket = new Socket(address, getPort());
					}
					socket.setKeepAlive(true);
					socket.setSoTimeout(sotimeout);
					close = !Send(socket, "CONN:120.24.179.52:9001");
					Log.i("socketClient", "建立连接成功：" + getIp() + ":" + getPort());
				} catch (Exception se) {
					Log.i("socketClient", "创建连接失败:" + getIp() + ":" + getPort());
					close = true;
				}
			}*/
		}
	}

	/**
	 * 发送数据，发送失败返回false,发送成功返回true
	 * 
	 * @param csocket
	 * @param message
	 * @return
	 */
	public Boolean Send(Socket csocket, String message) {

			PrintWriter out;
			try {
				out = new PrintWriter(csocket.getOutputStream());
				out.print(message);
				out.flush();
				return true;
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}

	}

	/**
	 * 读取数据，返回字符串类型
	 * 
	 * @param csocket
	 * @return
	 */
	public String ReadText(Socket csocket) {
		try {
			csocket.setSoTimeout(sotimeout);
			InputStream input = csocket.getInputStream();
			BufferedReader in = new BufferedReader(new InputStreamReader(input));

			int len = in.read(readBuf);
			if(len>0){
				String sc = new String(readBuf, 0, len);
				return sc;
			}else{
				return null;
			}
		} catch (IOException se) {
			return null;
		}
	}

	/**
	 * 判断是否断开连接，断开返回true,没有返回false
	 * 
	 * @param socket
	 * @return
	 */
	public Boolean isServerClose(Socket socket){
		try{
			socket.sendUrgentData('H');//发送1个字节的紧急数据，默认情况下，服务器端没有开启紧急数据处理，不影响正常通信
			//Send(socket, "HEARTBEAT");
			socket.getOutputStream().flush();
			return false;
		}catch(Exception se){
			Log.w("socketClient", "socket断开了，准备重连");
			MyApplication.clouldCtlUrl = "";
			return true;
		}
	}

	public String getIp() {
		return ip;
	}

	public void setIp() {
		if(MyCloudBackService.isNeedhttpProxy) {
			this.ip = MyCloudBackService.httpProxy;
		}else {
			this.ip = MyCloudBackService.cloudLogsServerIp;
		}
	}

	public Integer getPort() {
		return port;
	}

	public void setPort() {
		if(MyCloudBackService.isNeedhttpProxy) {
			this.port = 1080;
		}else {
			this.port = new Integer(MyCloudBackService.cloudLogsServerPort + 1);
		}
	}

}
